package com.atguigu.spzx.product.service.imple;

import com.atguigu.spzx.model.entity.product.Category;
import com.atguigu.spzx.product.mapper.CategoryMapper;
import com.atguigu.spzx.product.service.CategoryService;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CategoryServiceImpl implements CategoryService {
    @Resource
    CategoryMapper categoryMapper;
    @Resource
    RedisTemplate redisTemplate;
    @Cacheable(value = "index:cates" , key = "'one'")
    @Override
    public List<Category> findOneCategories() {
        //1、先查询缓存中是否有数据 如果有直接返回
//        Object catesCache = redisTemplate.opsForValue().get("index:cates:one");
//        if(catesCache!=null){
//            //查询到缓存
//            return (List<Category>) catesCache;
//        }

        //2、如果缓存没有数据 再查询数据库 并存到redis中
        //查询一级分类列表： 查询parent_id为0的分类
        List<Category> oneCategories = categoryMapper.findOneCategories();

//        redisTemplate.opsForValue().set("index:cates:one" , oneCategories, 600 ,
//                TimeUnit.SECONDS);
        return oneCategories;
    }
    @Cacheable(value = "index:cates" , key = "'all'")
    @Override
    public List<Category> findCategoryTree() {
        //查询所有的分类
        List<Category> categories = categoryMapper.findAllCategories();
        //-- 如果sql中实现父子数据查询绑定：sql需要多表联查、自定义解析查询结果集
        
        //业务将查询到的分类组装成父子嵌套集合
        //1、挑选出1级分类
        List<Category> oneCategoryList = categories.stream().filter(category -> category.getParentId().longValue() == 0)
                .collect(Collectors.toList());
        //2、为每个一级分类查询并设置它的下一级分类
        oneCategoryList.forEach(oneCategory->{
            //二级分类
            List<Category> twoCategoryList = categories.stream().filter(category ->
                            // 使用正在遍历的一级分类的id和 其他分类的parentid比较
                            category.getParentId().longValue() == oneCategory.getId().longValue())
                    .collect(Collectors.toList());
            oneCategory.setChildren(twoCategoryList);//设置子分类集合
            oneCategory.setHasChildren(!CollectionUtils.isEmpty(twoCategoryList));
            //给二级分类设置三级分类：
            twoCategoryList.forEach(twoCategory->{

                List<Category> threeCategoryList = categories.stream().filter(category ->
                                twoCategory.getId().longValue() == category.getParentId().longValue())
                        .collect(Collectors.toList());
                twoCategory.setChildren(threeCategoryList);
                twoCategory.setHasChildren(!CollectionUtils.isEmpty(threeCategoryList));

            });

        });
        return oneCategoryList;
    }


    /*
        spring-context提供了自动缓存管理：
        1、引入springcontext的依赖
        2、在启动类上启用自动缓存管理:
        3、实现spring提供的CacheManager接口：
                实现管理缓存的方法：  决定在哪里存储缓存
                引入的springboot dataredis启动器中提供了CacheManager的实现，可以使用redis管理缓存

            将缓存管理器注入到容器中
        4、在需要缓存管理的方法上使用缓存管理注解：
            @Cacheable注解： 使用在有返回结果的方法(查询方法)上   使用最多
                当方法执行前先查询缓存是否存在 如果存在直接返回缓存结果 不存在才执行方法得到返回结果存到缓存中
            @CachePut注解:  一般在新增方法上使用。当新增数据成功会自动将数据缓存起来
            @CacheEvict注解： 一般用在 删除/修改方法上 ， 当更新删除成功可以删除对应的缓存
     */
    //新增分类
    //value表示缓存的key    key表示缓存key中需要动态拼接的参数
    @CachePut(value = "test:cache" , key = "'cate:'+#category.id")
    //上面的value+key拼接的键：  test:cache::cate:id值
    public Category saveCate(Category category){ //业务代码中生成id
        categoryMapper.saveCate(category);
        return category;
    }
    //根据id查询分类
    @Cacheable(value = "test:cache" , key = "'cate:'+#id")
    public Category getById(Long id){
        System.out.println("查询数据库.......");
        return categoryMapper.getById(id);
    }
    //删除指定id的分类
    @CacheEvict(value = "test:cache" , key = "'cate:'+#id")
    public void deleteById(Long id){
        categoryMapper.deleteById(id);
    }
}
